<template>
  <div>
    <!--  通过button调用 input的点击事件 -->
    <input
      ref="excel-upload-input"
      class="excel-upload-input"
      type="file"
      accept=".xlsx, .xls"
      @change="handleClick"
    />
    <!-- 
      drag：拖拉过程中，在被拖拉的节点上持续触发（相隔几百毫秒）。
      dragenter：拖拉进入当前节点时，在当前节点上触发一次，该事件的target属性是当前节点。
                  通常应该在这个事件的监听函数中，指定是否允许在当前节点放下（drop）拖拉的数据。
      dragover：拖拉到当前节点上方时，在当前节点上持续触发（相隔几百毫秒），该事件的target属性是当前节点。
            该事件与dragenter事件的区别是，dragenter事件在进入该节点时触发，然后只要没有离开这个节点，dragover事件会持续触发。
     -->
    <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
      移动文件到此区域
      <el-button
        :loading="loading"
        style="margin-left: 16px"
        size="mini"
        type="primary"
        @click="handleUpload"
      >
        点击上传
      </el-button>
    </div>
    <!-- /////////////// 将解析后的Excel数据弹窗展示 并且显示是否上传到服务器//////// -->
    <table-dialog
      v-if="excelData.results != null"
      :dialogFormVisible.sync="dialogFormVisible"
      :excelData="excelData"
    ></table-dialog>
  </div>
</template>

<script>
import * as XLSX from 'xlsx'
import tableDialog from './cpns/tableDialog.vue'
export default {
  components: { tableDialog },
  data() {
    return {
      loading: false,
      excelData: {
        header: null,
        results: null,
      },
      dialogFormVisible: false,
    }
  },
  methods: {
    generateData({ header, results }) {
      // 调用 获取成功的函数
      this.excelData.header = header
      this.excelData.results = results
      console.log(this.excelData) // 打印结果
      this.dialogFormVisible = true
    },
    handleDrop(e) {
      e.stopPropagation() // 阻止事件冒泡
      e.preventDefault() // 阻止默认事件执行
      if (this.loading) return
      const files = e.dataTransfer.files
      // 是否只有一个文件
      if (files.length !== 1) {
        this.$message.error('只能上传一个文件!')
        return
      }
      const onlyFile = files[0]

      // 检查是否后缀为 .xlsx, .xls, .csv
      if (!this.isExcel(onlyFile)) {
        this.$message.error('只能上传后缀为 .xlsx, .xls, .csv 的文件')
        return false
      }
      this.upload(onlyFile) // 进行上传操作
      e.stopPropagation()
      e.preventDefault()
    },
    handleDragover(e) {
      e.stopPropagation()
      e.preventDefault()
      e.dataTransfer.dropEffect = 'copy'
    },
    handleUpload() {
      this.$refs['excel-upload-input'].click() // 调用input的点击事件
    },
    handleClick(e) {
      // console.log(e.target)
      // 获取到上传的文件数据 只获取第一个
      const onlyFile = e.target.files[0]
      if (!onlyFile) return this.$message.error('上传的文件有误')
      // 执行上传
      this.upload(onlyFile)
    },
    upload(onlyFile) {
      // 清空输入框
      this.$refs['excel-upload-input'].value = null
      // 是否有上传拦截操作函数 如果没有直接进入读取数据函数
      if (!this.beforeUpload) {
        this.readerData(onlyFile)
        return
      }
      const before = this.beforeUpload(onlyFile)
      if (before) {
        this.readerData(onlyFile)
      }
    },
    // 将上传的数据转为Excel数据
    readerData(onlyFile) {
      this.loading = true
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        // FileReader方法 readAsArrayBuffer(file) 按字节读取文件内容，结果用ArrayBuffer对象表示
        reader.readAsArrayBuffer(onlyFile)
        // FileReader事件 onload 当读取操作成功完成时调用
        reader.onload = (e) => {
          const data = e.target.result // 获取到 ArrayBuffer
          const workbook = XLSX.read(data, { type: 'array' }) // data转换  array(Uint8Array，8位无符号数组)
          const firstSheetName = workbook.SheetNames[0] // 第一张工作表名称
          const firstWorksheetData = workbook.Sheets[firstSheetName] // workbook.Sheets 存储对应工作表的数据 通过类似A1这样的键值保存每个单元格的内容 key表名 value 表数据
          const header = this.getHeaderRow(firstWorksheetData) // 获取 表头
          const results = XLSX.utils.sheet_to_json(firstWorksheetData) // 将数据转换json格式
          this.generateData({ header, results })
          this.loading = false
          resolve()
        }
      })
    },
    // 获取表头
    getHeaderRow(sheet) {
      const headers = []
      // 可以查看到sheet有多少行 {e:{c:结束列位置,r:结束行位置},s:{c:开始列位置,r:开始行位置}}
      const range = XLSX.utils.decode_range(sheet['!ref'])
      const R = range.s.r
      /* 遍历第一行 为表头 */
      for (let C = range.s.c; C <= range.e.c; ++C) {
        // XLSX.utils.encode_cell 获取到键名 sheet[键名]
        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
        const header = '未知内容' + C
        // 如果cell 存在并且有值 格式化输出内容
        if (cell && cell.t) header = XLSX.utils.format_cell(cell)
        headers.push(header)
      }
      return headers
    },
    isExcel(file) {
      return /\.(xlsx|xls|csv)$/.test(file.name)
    },
  },
}
</script>

<style scoped>
.excel-upload-input {
  display: none;
  z-index: -9999;
}
.drop {
  border: 2px dashed #bbb;
  width: 600px;
  height: 160px;
  line-height: 160px;
  margin: 0 auto;
  font-size: 24px;
  border-radius: 5px;
  text-align: center;
  color: #bbb;
  position: relative;
}
</style>
